<template>
    <div class="scroll-container" :style="paddingStyle">

        <div class="scroll-wrapper" ref="scroll" :style="wrapperStyle">
            <div class="scroll-content">
                <div v-for="(url, index) in images" :key="index"
                     class="scroll-item"
                     :style="{...itemStyle , ...itemSpaceStyle(index)}">
                    <slot :props="{url, index , onItemClick }">
                        <CloseImg v-if="closable" class="scroll-item-close" @click="onRemoveClick(index , url)"/>
                        <img :src="url" @click="onItemClick(index)" class="scroll-item-img">
                    </slot>
                </div>
                <slot name="add-button" :props="{onAddClick}" v-if="enableAdd">
                    <button class="btn-add scroll-item" @click="onAddClick" :style="addButtonStyle">
                        <AddImg class="btn-add-icon "/>
                    </button>
                </slot>
            </div>
        </div>
        <div class="scroll-nav" v-if="enableNav">
            <div class="scroll-arrow" @click="scrollByLeft">
                <button>
                    <ArrowImg class="img"/>
                </button>
            </div>
            <div class="scroll-arrow" @click="scrollByRight">
                <button>
                    <ArrowImg class="flip-x img"/>
                </button>
            </div>
        </div>
    </div>
</template>

<script>
    import BScroll from 'better-scroll'
    import AddImg from '../assets/add.svg';
    import ArrowImg from '../assets/arrow.svg';
    import CloseImg from '../assets/close.svg';

    export default {
        name: "vue-roll",
        components: {AddImg, ArrowImg, CloseImg},
        data() {
            return {
                bScroll: null,
                realMoveDistance: 0,
                defaultMoveDistance: '30%',
                moveTime: 0,
                defaultMoveSpeed: 500,
            }
        },
        props: {
            images: {
                type: Array
            },
            width: {
                type: [String, Number],
                default: '100%'
            },
            itemSpace: {
                type: [Number, String],
                default: 20
            },
            itemSize: {
                type: Object,
                default: () => ({
                    height: '200px'
                })
            },
            /* 点击箭头按钮移动的距离, 可以是百分比数据 */
            moveDistance: {
                type: [Number, String]
            },
            /* 以秒为单位 */
            moveSpeed: {
                type: Number
            },
            contentAlign: {
                type: String,
                default: 'left',
                validator: value => ['left', 'right', 'center'].indexOf(value) >= 0
            },
            padding: {
                type: [String, Object, Number],
                default: 0
            },
            enableNav: {
                type: Boolean,
                default: true
            },
            enableAdd: {
                type: Boolean,
                default: true
            },
            /* item 是否可以删除 */
            closable: {
                type: Boolean,
                default: false
            },
            /* 开启可移除Item时默认填充10px padding */
            closablePadding: {
                type: Boolean,
                default: true
            }
        },
        watch: {
            moveDistance(now) {
                this.calMoveDistance(now)
            },
            images() {
                // item 变化时重新计算距离
                this.$nextTick(() => {
                    // 手动刷新一次
                    this.bScroll.refresh();
                    this.calMoveDistance(this.moveDistance || this.defaultMoveDistance);
                })
            }
        },
        mounted() {
            this.bScroll = new BScroll(this.$refs.scroll, {
                scrollX: true,
                // 当元素变化时，需要手动调用refresh
                observeDOM: false
            });
            this.calMoveDistance(this.moveDistance || this.defaultMoveDistance);
        },
        beforeDestroy() {
            this.bScroll.destroy()
        },
        methods: {
            calMoveDistance(distance) {
                const type = typeof distance;
                if (type === 'number') {
                    this.realMoveDistance = distance;
                } else {
                    if (type === 'string') {
                        if (distance.indexOf('%') > 0) {
                            const w = this.$refs.scroll.clientWidth;
                            this.realMoveDistance = w * parseFloat(distance) * 0.01;
                        } else {
                            this.realMoveDistance = parseFloat(distance);
                            if (isNaN(this.realMoveDistance)) {
                                this.calMoveDistance(this.defaultMoveDistance)
                            }
                        }
                    }
                }
                this.realMoveDistance = Math.min(Math.abs(this.bScroll.maxScrollX), Math.abs(this.realMoveDistance));
                this.moveTime = this.realMoveDistance / this.getSpeed() * 1000;
            },
            scrollByLeft() {
                let currentX = this.bScroll.x;
                let maxX = this.bScroll.maxScrollX;

                if (currentX > maxX) {
                    let distance = -this.realMoveDistance;
                    let time = this.moveTime;
                    if (currentX + distance <= maxX) {
                        distance = maxX - currentX;
                        time = Math.abs(distance) / this.getSpeed() * 1000;
                    }
                    this.bScroll.scrollBy(distance, 0, time);
                }
            },
            scrollByRight() {
                let currentX = this.bScroll.x;
                if (currentX < 0) {
                    let distance = this.realMoveDistance;
                    let time = this.moveTime;
                    if (currentX + distance >= 0) {
                        distance = Math.abs(currentX);
                        time = distance / this.getSpeed() * 1000;
                    }
                    this.bScroll.scrollBy(distance, 0, time);
                }
            },
            onItemClick(index) {
                this.$emit("onItemClick", index)
            },
            onAddClick() {
                this.$emit('onAdd');
            },
            onRemoveClick(index, url) {
                this.$emit('onRemove', index, url);
            },
            getSpeed() {
                if (this.moveSpeed === 0 || isNaN(this.moveSpeed)) {
                    return this.defaultMoveSpeed
                } else {
                    return Math.abs(this.moveSpeed);
                }
            },
            itemSpaceStyle(index) {
                if (index === 0) {
                    return null
                }
                if ("string" === typeof this.itemSpace) {
                    return {'margin-left': this.itemSpace}
                } else if ('number' === typeof this.itemSpace) {
                    return {'margin-left': this.itemSpace + 'px'}
                }
                return null;
            }
        },
        computed: {
            itemStyle() {
                return {...this.itemSize};
            },
            wrapperStyle() {
                const style = {
                    'text-align': this.contentAlign
                };
                if (this.closable && this.closablePadding) {
                    style['padding'] = '10px 0';
                }
                return style
            },
            paddingStyle() {
                let style = {};
                if ("string" === typeof this.padding) {
                    style['padding'] = this.padding;
                } else if ('number' === typeof this.padding) {
                    style['padding'] = this.padding + 'px';
                } else {
                    style = {...this.padding}
                }
                return style
            },
            addButtonStyle() {
                return {
                    height: this.itemSize.height
                    , ...this.itemSpaceStyle(1)
                }
            }
        }
    }
</script>
